
set eStandardNameLength 10

proc createLayout {class name parent args} {
	set layout [$class #auto $args]
	[$parent getSequence] acquire $name $layout
	return $layout
}

proc activateLayout {class name parent args} {
	set layout [$class #auto $args]
	[$parent getSequence] acquire $name $layout
	$layout activate
	return $layout
}

proc triggerLayout {class name parent args} {
	set layout [$class #auto $args]
	[$parent getSequence] acquire $name $layout
	$parent addTriggerPath [list $name]
	return $layout
}

proc sequenceLayout {class name parent args} {
	set layout [$class #auto $args]
	[$parent getSequence] acquire $name $layout
	$parent addLayoutPath [list $name]
	return $layout
}

proc decorateLayout {class name parent args} {
	set layout [$class #auto $args]
	[$parent getSequence] acquire $name $layout
	$parent setLayoutPath [list $name]
	return $layout
}

proc insertLayout {class name parent args} {
	if [$parent isa SequenceLayout] {
		eval [list sequenceLayout $class $name $parent] $args
	} else {
		eval [list decorateLayout $class $name $parent] $args
	}
}

# A report will create a dict containing Start, Write and Finish functions, but optionally you can
# add a DrawLayoutBorder function in three different ways, and even set its color.
# The DrawLayoutBorder contents are set using the drawLayoutBorderFlags, a number consisting of a bit combination
# between 0 and 7. Bit 0: Draws a border around every column; Bit 1: Draws the initial border showing
# the required minimum dimensions in a dashed line; Bit 2: Writes digits around the edge of each
# column, starting with 1 in the upper left corner and incrementing both towards the right and downwards,
# continuing after reaching the upper right and lower left corners to join again at the lower right corner.
# Can give an idea of how many characters can fit in the column.
# Other options can alter the behavior of the Start, Write and Finish functions.
proc createBorder {drawLayoutBorder name drawLayoutBorders ancestor path acts variables args} {
	if {$drawLayoutBorder == 0} return
	lappend variables Left Bottom Width Height

	set play [eval [list createPlay $name $drawLayoutBorders] $args]
	$play setFront {$BorderColor} 

	if {$drawLayoutBorder & 4} {
		lappend variables LineLength BoxLength
		includePart WriteBoxFrameBorder $play $acts
	}
	if {$drawLayoutBorder & 2} {
		lappend variables InitialWidth InitialHeight
		includePart DrawInitialBoxFrameBorder $play $acts
	}
	if {$drawLayoutBorder & 1} {
		includePart DrawBoxFrameBorder $play $acts
	}

	set attributes {}
	foreach variable $variables {
		lappend attributes \$$variable \$$name$variable
	}
	$play updateAttributes $attributes
	
	$ancestor addReference $name $path $variables
}

# hasHeading values:
#  0: no heading
#  1: heading
#  2: empty separator line
#  3: empty separator line and heading
proc createReportLayout {name parent acts hasHeading nrOfColumns allowsOverlap
	cellWidth cellHeight lineLength totalBoxLength
	headingName reportName writeName transformName
	drawLayoutBorder drawLayoutBorders ancestor path borderArgs
	args} {
	# Lengths ending in "!" are taken as absolute values, i.e. their corresponding
	# dimension can't be altered.
	if {[set limitWidth [string equal [string range $lineLength end end] "!"]]} {
		set lineLength [string range $lineLength 0 end-1]
	}
	if {[set limitHeight [string equal [string range $totalBoxLength end end] "!"]]} {
		set totalBoxLength [string range $totalBoxLength 0 end-1]
	}
	
	set addHeadingName 0
	if $hasHeading {
		#set layout [$addLayout $name $parent VerticalStackLayout $parent {}]
		#set heading [$addLayout "${name}Heading" GridLayout $layout cellWidth $cellWidth cellHeight $cellHeight \
		#	  lineLength [string length $name] boxLength 1 limitHeight 2]
		set headingWidth 0
		set headingHeight 0
		switch $hasHeading 1 {
			set headingWidth "[string length $headingName] $cellWidth mul"
			set headingHeight $cellHeight
			set addHeadingName 1
		} 2 {
			set headingHeight $cellHeight
		} 3 {
			set headingWidth "[string length $headingName] $cellWidth mul"
			set headingHeight "$cellHeight 2 mul"
			set addHeadingName 1
		}
		set layout [createLayout FrameLayout $name $parent \
			topMarginHeight $headingHeight width $headingWidth]
		if $addHeadingName {
			$layout updateAttributes [list \
				\$HeadingX {$Left $HeadingFontBaseX add} \$HeadingY {$Bottom $Height add $HeadingFontBaseY add} \
				\$HeadingName [Story::toString $headingName] \
			]
		}
		set parent $layout
		lappend path $name
	}
	
	if {$nrOfColumns > 1} {
		set columns [createLayout HorizontalStackLayout $name $parent \
			gapWidth "$cellWidth \$TextGapLineLength mul" fillAlgorithm equalFill \
			\$CellWidth $cellWidth \$CellHeight $cellHeight \
			\$StartX {$Left $TextFontBaseX add} \$StartY {$Bottom $Height add $TextFontBaseY add} \
			\$StopY {$Bottom $TextFontBaseY add}]

		set report [createChapter $name $columns type dict define def]
		set steps [createChapter Steps $report type array define {}]
		
		set boxLength "$totalBoxLength $nrOfColumns add 1 sub $nrOfColumns idiv"

		if $allowsOverlap {
		
			set overlapLength \$${nrOfColumns}LineLength
			set countOverlapsHead ""
			set countOverlapsTail ""
			set attributes [list \$TotalBoxLength "\$BoxLength $nrOfColumns mul"]
			for {set idx [expr $nrOfColumns - 1]; set cnt 1} {$idx > 0} {incr idx -1; incr cnt} {
				append overlapLength " \$${idx}LineLength \$TextGapLineLength add add"
				lappend attributes \$${idx}OverlapLength $overlapLength \
					\$${idx}CountOverlaps [concat $countOverlapsHead "0 gt \{ [expr $cnt + 1] \} \{ $cnt \} ifelse" $countOverlapsTail]
				set countOverlapsHead [concat "dup 0 gt \{ \$${idx}LineLength \$TextGapLineLength add sub" $countOverlapsHead]
				set countOverlapsTail [concat "\}\{ pop $cnt \} ifelse" $countOverlapsTail]
			}
			$columns updateAttributes $attributes
		
			set idx 1
		
			set column [eval [list sequenceLayout GridLayout $idx $columns \
				cellWidth $cellWidth cellHeight $cellHeight \
				lineLength $lineLength boxLength $boxLength \
				limitWidth $limitWidth limitHeight $limitHeight] $args]

			$columns addReference $idx $idx {Left Bottom Width Height LineLength BoxLength}

			[alterPart TextOverlapFirstColumnSteps $idx $steps $acts] updateAttributes [list \
				\$Left \$${idx}Left \$Bottom \$${idx}Bottom \$Width \$${idx}Width \$Height \$${idx}Height \
				\$LineLength \$${idx}LineLength \$BoxLength \$${idx}BoxLength \
				\$OverlapLength \$${idx}OverlapLength \$CountOverlaps \$${idx}CountOverlaps]

			for {set idx 2} {$idx < $nrOfColumns} {incr idx} {
				set column [eval [list sequenceLayout GridLayout $idx $columns \
					cellWidth $cellWidth cellHeight $cellHeight \
					lineLength $lineLength boxLength $boxLength \
					limitWidth $limitWidth limitHeight $limitHeight] $args]

				$columns addReference $idx $idx {Left Bottom Width Height LineLength BoxLength}

				[alterPart TextOverlapColumnSteps $idx $steps $acts] updateAttributes [list \
					\$Left \$${idx}Left \$Bottom \$${idx}Bottom \$Width \$${idx}Width \$Height \$${idx}Height \
					\$LineLength \$${idx}LineLength \$BoxLength \$${idx}BoxLength \
					\$OverlapLength \$${idx}OverlapLength \$CountOverlaps \$${idx}CountOverlaps]
			}

			set column [eval [list sequenceLayout GridLayout $idx $columns \
				cellWidth $cellWidth cellHeight $cellHeight \
				lineLength $lineLength boxLength $boxLength \
				limitWidth $limitWidth limitHeight $limitHeight] $args]

			$columns addReference $idx $idx {Left Bottom Width Height LineLength BoxLength}

			[alterPart TextOverlapLastColumnSteps $idx $steps $acts] updateAttributes [list \
				\$Left \$${idx}Left \$Bottom \$${idx}Bottom \$Width \$${idx}Width \$Height \$${idx}Height \
				\$LineLength \$${idx}LineLength \$BoxLength \$${idx}BoxLength]

		} else {

			for {set idx 1} {$idx < $nrOfColumns} {incr idx} {
				set column [eval [list sequenceLayout GridLayout $idx $columns \
					cellWidth $cellWidth cellHeight $cellHeight \
					lineLength $lineLength boxLength $boxLength \
					limitWidth $limitWidth limitHeight $limitHeight] $args]

				$columns addReference $idx $idx {Left Bottom Width Height LineLength BoxLength}

				[alterPart TextColumnSteps $idx $steps $acts] updateAttributes [list \
					\$Left \$${idx}Left \$Bottom \$${idx}Bottom \$Width \$${idx}Width \$Height \$${idx}Height \
					\$LineLength \$${idx}LineLength \$BoxLength \$${idx}BoxLength]
			}

			set column [eval [list sequenceLayout GridLayout $idx $columns \
				cellWidth $cellWidth cellHeight $cellHeight \
				lineLength $lineLength boxLength $boxLength \
				limitWidth $limitWidth limitHeight $limitHeight] $args]

			$columns addReference $idx $idx {Left Bottom Width Height LineLength BoxLength}

			[alterPart TextLastColumnSteps $idx $steps $acts] updateAttributes [list \
				\$Left \$${idx}Left \$Bottom \$${idx}Bottom \$Width \$${idx}Width \$Height \$${idx}Height \
				\$LineLength \$${idx}LineLength \$BoxLength \$${idx}BoxLength]

		}
		
		if {$drawLayoutBorder != 0} {
			for {set idx 1} {$idx <= $nrOfColumns} {incr idx} {
				eval [list createBorder $drawLayoutBorder $name$idx $drawLayoutBorders $ancestor [concat $path $name $idx] $acts CellHeight \
					\$InitHeight "\$Height $totalBoxLength \$CellHeight mul [expr $idx - 1] \$Height mul sub min 0 max"] $borderArgs
			}
		}

		if {!$hasHeading} {
			set layout $columns
		}
	} else {
		set boxLength $totalBoxLength
		
		set column [eval [list createLayout GridLayout $name $parent \
			cellWidth $cellWidth cellHeight $cellHeight \
			lineLength $lineLength boxLength $boxLength \
			limitWidth $limitWidth limitHeight $limitHeight \
			\$StartX {$Left $TextFontBaseX add} \$StartY {$Bottom $Height add $TextFontBaseY add} \
			\$StopY {$Bottom $TextFontBaseY add}] $args]

		eval [list createBorder $drawLayoutBorder $name $drawLayoutBorders $ancestor [concat $path $name] $acts {}] $borderArgs

		set report [createChapter $name $column type dict define def]
		set steps [createChapter Steps $report type array define {}]

		includePart TextLastColumnSteps $steps $acts

		if {!$hasHeading} {
			set layout $column
		}
	}

	set start [createChapter Start $report type proc define bind]
	$start setAct {
		"$SetTextFont"
		"/StepIndex 0 def"
		"/Step Steps 0 get def"
		"/Finish {} def"
	}
	set write [createChapter Write $report type proc define bind]
	if {[string length $transformName]} {
		$write setFront [list $transformName]
	}
	includePart IterateSplitString $write $acts

	if $addHeadingName {
		$start prependToAct {
			"$SetHeadingFont"
			"$HeadingX# $HeadingY# moveto"
			"$HeadingName $ShowHeading"
		}
	}
	if $hasHeading {
		$layout setLayoutPath $name
	}

	[createChapter $reportName $layout] setAct [list \
		\$SwitchToTextMode \
		"$name begin Start end" \
		"/FinishReport /Finish$reportName load def" \
	]
	[createChapter $writeName $layout] setAct [list "$name begin Write end"]
	[createChapter "Finish$reportName" $layout] setAct [list "$name begin Finish end"]

	return $layout
}

proc muteReport {layout reportName writeName} {
	createChapter $reportName $layout
	[createChapter $writeName $layout] setAct "pop"
}

proc muteTitle {layout} {
	[createChapter DrawTitle $layout] setAct "pop"
}

proc insertReportLayout {name parent args} {
	set layout [eval [list createReportLayout $name $parent] $args]
	if [$parent isa SequenceLayout] {
		$parent addLayoutPath $name
	} else {
		$parent setLayoutPath $name
	}
	return $layout
} 

proc createTitleLayout {name parent acts 
	cellWidth cellHeight
	boardTitleWidth boardTitleHeight
	gameTitleWidth gameTitleHeight
	drawLayoutBorder drawLayoutBorders ancestor path borderArgs
	args} {
	set gridLayout [eval [list createLayout GridLayout $name $parent \
		cellWidth $cellWidth cellHeight $cellHeight] $args]
	set drawTitle [createChapter DrawTitle $gridLayout]
	$drawTitle setFront \$SwitchToTextMode

	set stackLayout [decorateLayout VerticalStackLayout TitleStack $gridLayout]

	set boardLayout [sequenceLayout Layout Board $stackLayout \
		width $boardTitleWidth height $boardTitleHeight limitHeight 1]
	eval [list createBorder [expr $drawLayoutBorder & 3] BoardTitle $drawLayoutBorders $ancestor [concat $path Title TitleStack Board] $acts {}] $borderArgs
	$gridLayout addReference BoardTitle {TitleStack Board} {Left Bottom Width Height}

	set gameLayout [sequenceLayout Layout Game $stackLayout \
		width $gameTitleWidth height $gameTitleHeight limitHeight 1]
	eval [list createBorder [expr $drawLayoutBorder & 3] GameTitle $drawLayoutBorders $ancestor [concat $path Title TitleStack Game] $acts {}] $borderArgs
	$gridLayout addReference GameTitle {TitleStack Game} {Left Bottom Width Height}

	set writeBoardTitle [createPlay WriteBoardTitle $drawTitle \
		\$Left \$BoardTitleLeft \$Bottom \$BoardTitleBottom \
		\$Width \$BoardTitleWidth \$Height \$BoardTitleHeight \
		\$BaseX \$BoardTitleFontBaseX \$BaseY \$BoardTitleFontBaseY]
	$writeBoardTitle setFront {
		"$SetBoardTitleFont"
		"$BoardTitle"
	}
	includePart WriteTitle $writeBoardTitle $acts
	set writeGameTitle [createPlay WriteGameTitle $drawTitle \
		\$Left \$GameTitleLeft \$Bottom \$GameTitleBottom \
		\$Width \$GameTitleWidth \$Height \$GameTitleHeight \
		\$BaseX \$GameTitleFontBaseX \$BaseY \$GameTitleFontBaseY]
	$writeGameTitle setFront {
		"$SetGameTitleFont"
	}
	includePart FitTitle $writeGameTitle $acts
}

proc sequenceTitleLayout {name parent args} {
	set layout [eval [list createTitleLayout $name $parent] $args]
	$parent addLayoutPath $name
	return $layout
} 

# Types of layout:
#   image : Only the map image is displayed. (default)
#   corner cornerBox shape : One report box is in or extends to the bottom right corner.
#     cornerBox = owners | adjustments | retreats (default) | orders
#     shape = flat (default) | fold | magnet
#       fold: Only if cornerBox is owners or orders; puts adjustments and retreats next to (orders) or on top of (owners) each other.
#       magnet: Only if cornerBox is orders; puts adjustments and retreats next to each other below owners
#   side position shape : All reports are on one side.
#     position = right (default) | bottom
#     shape = flat (default) | fold | magnet
#       fold: Puts adjustments and retreats next to (right) or on top of (bottom) each other.
#       magnet: Puts adjustments and retreats next to each other below owners
set cPageLayoutDefaults [iarray::Array #auto \
	layout image \
	fontSize 8 \
	nrOfAdjustments 2 \
	ownerInfoLength 7 \
	territoryNameLength 3 \
	coastNameLength 3 \
	unitNameLength 1 \
	orderTypeLength 1 \
	orderIndentLength 1 \
	orderResultLength 9 \
	retreatResultLength 9 \
	adjustmentTypeLength 7 \
	adjustmentActionLength 6 \
	retreatActionLength 7 \
	\
	gapLineLength \$TextGapLineLength \
	gapBoxLength 1 \
	\
	boardTitle Diplomacy \
	gameTitle "Diplomacy, Winter 1900" \
	boardTitleFontSizeRatio 3 \
	gameTitleFontSizeRatio 2 \
	\
	pageMarginWidth 20 \
	pageMarginHeight 20 \
	imageFrameMarginWidth \$FrameMarginWidth \
	imageFrameMarginHeight \$FrameMarginHeight \
	ownerColumns 1 \
	adjustmentColumns 1 \
	retreatColumns 1 \
	orderColumns 1 \
	ownerAllowsOverlap 0 \
	adjustmentAllowsOverlap 0 \
	retreatAllowsOverlap 0 \
	orderAllowsOverlap 0 \
	ownerHeading Owners \
	adjustmentHeading Adjustments \
	retreatHeading Retreats \
	orderHeading Orders \
	ownerNameKey {} \
	adjustmentNameKey {} \
	retreatNameKey {} \
	orderNameKey {} \
	ownerNameLength $eStandardNameLength \
	adjustmentNameLength $eStandardNameLength \
	retreatNameLength $eStandardNameLength \
	orderNameLength $eStandardNameLength \
	\
	nrOfPowers 0 \
	nrOfSupplies 0 \
	imageWidth 0 \
	imageHeight 0 \
	\
	drawLayoutBorder 7
]

proc createPageLayout {name parent acts colorTracker args} {
	global cPageLayoutDefaults eStandardNameLength

	set pageLayoutDetails [iarray::Array #auto [$cPageLayoutDefaults get]]
	$pageLayoutDetails set $args

	foreach {key value} [$pageLayoutDetails get] {set $key $value}

	# Formulas.
	if {![$pageLayoutDetails has ownerHasHeading]} {set ownerHasHeading 0}
	if {![$pageLayoutDetails has adjustmentHasHeading]} {set adjustmentHasHeading 0}
	if {![$pageLayoutDetails has retreatHasHeading]} {set retreatHasHeading 0}
	if {![$pageLayoutDetails has orderHasHeading]} {set orderHasHeading 0}
	if {![$pageLayoutDetails has nrOfOwnerSupplies]} {
		set nrOfOwnerSupplies "$nrOfSupplies 2 idiv"
	}
	if {![$pageLayoutDetails has boardTitleFontSize]} {
		set boardTitleFontSize "$fontSize $boardTitleFontSizeRatio mul"
	}
	if {![$pageLayoutDetails has boardTitleWidth]} {
		set boardTitleWidth "\$BoardTitleFontWidth [string length $boardTitle] mul"
	}
	if {![$pageLayoutDetails has boardTitleHeight]} {
		set boardTitleHeight "\$BoardTitleFontHeight"
	}
	if {![$pageLayoutDetails has gameTitleFontSize]} {
		set gameTitleFontSize "$fontSize $gameTitleFontSizeRatio mul"
	}
	if {![$pageLayoutDetails has gameTitleWidth]} {
		set gameTitleWidth "\$GameTitleFontWidth [string length $gameTitle] mul"
	}
	if {![$pageLayoutDetails has gameTitleHeight]} {
		set gameTitleHeight "\$GameTitleFontHeight"
	}
	if {![$pageLayoutDetails has cellWidth]} {set cellWidth \$TextFontWidth}
	if {![$pageLayoutDetails has cellHeight]} {set cellHeight \$TextFontHeight}
	if {![$pageLayoutDetails has gapWidth]} {set gapWidth "$cellWidth $gapLineLength mul"}
	if {![$pageLayoutDetails has gapHeight]} {set gapHeight "$cellHeight $gapBoxLength mul"}
	if {![$pageLayoutDetails has orderLineLength]} {set orderLineLength "$orderIndentLength $unitNameLength add $territoryNameLength 1 add 3 mul add $coastNameLength add $orderTypeLength 1 add 2 mul add $orderResultLength 2 add add $orderNameLength max"} 
	if {![$pageLayoutDetails has ownerLineLength]} {set ownerLineLength "$ownerNameLength $ownerInfoLength 1 add add $territoryNameLength 1 add $nrOfOwnerSupplies mul add"}
 	if {![$pageLayoutDetails has ownerBoxLength]} {set ownerBoxLength "$nrOfPowers 1 add"}
	if {![$pageLayoutDetails has adjustmentLineLength]} {set adjustmentLineLength "$adjustmentNameLength $adjustmentTypeLength 1 add add $unitNameLength 1 add $territoryNameLength 1 add add 1 add $nrOfAdjustments mul $coastNameLength add $adjustmentActionLength 1 add max add"}
	if {![$pageLayoutDetails has adjustmentBoxLength]} {set adjustmentBoxLength $nrOfPowers}
	if {![$pageLayoutDetails has orderBoxLength]} {set orderBoxLength "$nrOfPowers $nrOfSupplies add"}
	if {![$pageLayoutDetails has retreatLineLength]} {set retreatLineLength "$retreatNameLength $unitNameLength 1 add add $territoryNameLength 1 add add $coastNameLength add $orderTypeLength 1 add $territoryNameLength 1 add add $retreatResultLength 1 add add $retreatActionLength 1 add max add"}
	# Formula that climbs sublinearly. Extra line for the title.
	if {![$pageLayoutDetails has retreatBoxLength]} {set retreatBoxLength "$nrOfSupplies 3 div sqrt round 2 mul"}
	
	set pageLayout [activateLayout FrameLayout $name $parent \$BorderColor [$colorTracker addColor Black $drawLayoutBorder] \
		type proc define bd \
		width \$PageWidth height \$PageHeight fitWidth 1 fitHeight 1 \
		marginWidth $pageMarginWidth marginHeight $pageMarginHeight \
		\$FontSize $fontSize \
		\$TextFontSize $fontSize \
		\$CellWidth $cellWidth \$CellHeight $cellHeight \
		\$SetTextFont {TextFixedFont $TextFontSize# y z} \
		\$HeadingFontSize $fontSize \
		\$SetHeadingFont {TextHeadingFont $HeadingFontSize# y z} \
		\$BoardTitleFontSize $boardTitleFontSize \$BoardTitle [Story::toString $boardTitle] \
		\$SetBoardTitleFont {TextTitleFont $BoardTitleFontSize# y z} \
		\$GameTitleFontSize $gameTitleFontSize \
		\$SetGameTitleFont {TextTitleFont $GameTitleFontSize# y z} \
	]

	set drawLayoutBorders [createChapter DrawLayoutBorders $pageLayout \
		\$InitLeft \$Left \$InitBottom {$Bottom $Height add $InitHeight sub} \
		\$InitWidth \$InitialWidth \$InitHeight \$InitialHeight \
		\$TopX {$Left $TextFontBaseX add} \$TopY {$Bottom $Height add $CellHeight $FontSize sub 2 div sub $FontSize sub $TextFontBaseY add} \
		\$FirstLine {$TopX# $TopY# moveto} \
		\$NewLine {$CellHeight# sub moveto}]
	$drawLayoutBorders setFront {
		"s"
		"$SetTextFont"
	}
	$drawLayoutBorders setBack "r"

	set orderTransform {}
	if {[string length $orderNameKey]} {
		set orderTransform ReplaceOrderName
		set replaceOrderName [createChapter $orderTransform $pageLayout \$NameKey [Story::toName $orderNameKey]]
		set identifyPowerName [alterPart IdentifyPowerName {} $replaceOrderName $acts]
		# In the case of vassal powers, isolate and replace the first part only.
		includePart IsolatePowerName $identifyPowerName $acts
		includePart ReplacePowerName $identifyPowerName $acts
		set unpackPowerName [alterPart UnpackPowerName {} $identifyPowerName $acts]
		includePart ReplacePowerName $unpackPowerName $acts
		includePart ReattachPowerName $identifyPowerName $acts
	}
	set ownerTransform {}
	if {[string length $ownerNameKey] || ($ownerNameLength != $eStandardNameLength)} {
		set ownerTransform ReplaceOwnerName
		set replaceOwnerName [createChapter $ownerTransform $pageLayout \$NameLength $ownerNameLength]
		# Cascading to deal with vassal powers
		set cascadePowerName [alterPart CascadePowerName {} $replaceOwnerName $acts]
		$cascadePowerName appendToFront {
			"1 dict begin"
			"$NameLength 2 index { 1 sub } if /NameLength xd"
		}
		$cascadePowerName prependToBack end
		set identifyPowerName [alterPart IdentifyPowerName {} $cascadePowerName $acts]
		$identifyPowerName updateAttributes [list \$NameLength NameLength]
		includePart IsolatePowerName $identifyPowerName $acts
		if {[string length $ownerNameKey]} {
			$identifyPowerName updateAttributes [list \$NameKey [Story::toName $ownerNameKey]]
			includePart ReplacePowerName $identifyPowerName $acts
		}
		includePart WidenPowerName $identifyPowerName $acts
	}
	set adjustmentTransform {}
	if {[string length $adjustmentNameKey] || ($adjustmentNameLength != $eStandardNameLength)} {
		set adjustmentTransform ReplaceAdjustmentName
		set replaceAdjustmentName [createChapter $adjustmentTransform $pageLayout \$NameLength $adjustmentNameLength]
		set identifyPowerName [alterPart IdentifyPowerName {} $replaceAdjustmentName $acts]
		includePart IsolatePowerName $identifyPowerName $acts
		if {[string length $adjustmentNameKey]} {
			$identifyPowerName updateAttributes [list \$NameKey [Story::toName $adjustmentNameKey]]
			includePart ReplacePowerName $identifyPowerName $acts
		}
		includePart WidenPowerName $identifyPowerName $acts
	}
	set retreatTransform {}
	if {[string length $retreatNameKey] || ($retreatNameLength != $eStandardNameLength)} {
		if {[string equal $retreatNameKey $adjustmentNameKey] && ($retreatNameLength == $adjustmentNameLength)} {
			set retreatTransform $adjustmentTransform
		} else {
			set retreatTransform ReplaceRetreatName
			set replaceRetreatName [createChapter $retreatTransform $pageLayout \$NameLength $retreatNameLength]
			set identifyPowerName [alterPart IdentifyPowerName {} $replaceRetreatName $acts]
			includePart IsolatePowerName $identifyPowerName $acts
			if {[string length $retreatNameKey]} {
				$identifyPowerName updateAttributes [list \$NameKey [Story::toName $retreatNameKey]]
				includePart ReplacePowerName $identifyPowerName $acts
			}
			includePart WidenPowerName $identifyPowerName $acts
		}
	}

	# Initialize parent layouts and paths
	foreach part {image owner adjustment retreat order title} {
		set ${part}ParentLayout {}
		set ${part}Path {}
	}
	
	linit $layout layoutType image
	switch $layoutType image {
		set imageParentLayout $pageLayout
		set imagePath {}
	} corner {
		# Create the stacks according to which box is in the bottom right corner.
		linit [lrange $layout 1 end] {cornerBox shape} {retreats flat}
		switch $cornerBox owners {
			set pagePaneLayout [decorateLayout VerticalStackLayout PagePane $pageLayout \
				gapHeight $gapHeight]
			set topPaneLayout [sequenceLayout HorizontalStackLayout TopPane $pagePaneLayout \
				gapWidth $gapWidth leftToRight false]
			set rightPaneLayout [sequenceLayout VerticalStackLayout RightPane $topPaneLayout \
				fillAlgorithm equalFill bottomToTop true]
			set imageParentLayout $topPaneLayout
			set ownerParentLayout $pagePaneLayout
			set adjustmentParentLayout $rightPaneLayout
			set retreatParentLayout $rightPaneLayout
			set orderParentLayout $rightPaneLayout
			set titleParentLayout $rightPaneLayout
			# Paths
			set imagePath {PagePane TopPane}
			set ownerPath {PagePane}
			set adjustmentPath {PagePane TopPane RightPane}
			set retreatPath {PagePane TopPane RightPane}
			set orderPath {PagePane TopPane RightPane} 
			set titlePath {PagePane TopPane RightPane}
			# Minor headings.
			if {![$pageLayoutDetails has adjustmentHasHeading]} {set adjustmentHasHeading 1}
			if {![$pageLayoutDetails has retreatHasHeading]} {set retreatHasHeading 1}
		} adjustments {
			set pagePaneLayout [decorateLayout HorizontalStackLayout PagePane $pageLayout \
				gapWidth $gapWidth]
			set leftPaneLayout [sequenceLayout VerticalStackLayout LeftPane $pagePaneLayout \
				gapHeight $gapHeight]
			set rightPaneLayout [sequenceLayout VerticalStackLayout RightPane $pagePaneLayout \
				fillAlgorithm equalFill bottomToTop true]
			set imageParentLayout $leftPaneLayout
			set ownerParentLayout $leftPaneLayout
			set adjustmentParentLayout $rightPaneLayout
			set retreatParentLayout $rightPaneLayout
			set orderParentLayout $rightPaneLayout
			set titleParentLayout $rightPaneLayout
			# Paths
			set imagePath {PagePane LeftPane}
			set ownerPath {PagePane LeftPane}
			set adjustmentPath {PagePane RightPane}
			set retreatPath {PagePane RightPane}
			set orderPath {PagePane RightPane} 
			set titlePath {PagePane RightPane}
			# Minor headings.
			if {![$pageLayoutDetails has adjustmentHasHeading]} {set adjustmentHasHeading 1}
			if {![$pageLayoutDetails has retreatHasHeading]} {set retreatHasHeading 1}
		} retreats {
			set pagePaneLayout [decorateLayout HorizontalStackLayout PagePane $pageLayout \
				gapWidth $gapWidth]
			set leftPaneLayout [sequenceLayout VerticalStackLayout LeftPane $pagePaneLayout \
				gapHeight $gapHeight bottomToTop true]
			set bottomPaneLayout [sequenceLayout HorizontalStackLayout BottomPane $leftPaneLayout \
				gapWidth $gapWidth fillAlgorithm equalFill]
			set rightPaneLayout [sequenceLayout VerticalStackLayout RightPane $pagePaneLayout \
				fillAlgorithm equalFill bottomToTop true]
			set imageParentLayout $leftPaneLayout
			set ownerParentLayout $bottomPaneLayout
			set adjustmentParentLayout $bottomPaneLayout
			set retreatParentLayout $rightPaneLayout
			set orderParentLayout $rightPaneLayout
			set titleParentLayout $rightPaneLayout
			# Paths
			set imagePath {PagePane LeftPane}
			set ownerPath {PagePane LeftPane BottomPane}
			set adjustmentPath {PagePane LeftPane BottomPane}
			set retreatPath {PagePane RightPane}
			set orderPath {PagePane RightPane} 
			set titlePath {PagePane RightPane}
			# Minor headings.
			if {![$pageLayoutDetails has retreatHasHeading]} {set retreatHasHeading 1}
		} orders {
			set pagePaneLayout [decorateLayout HorizontalStackLayout PagePane $pageLayout \
				gapWidth $gapWidth]
			set leftPaneLayout [sequenceLayout VerticalStackLayout LeftPane $pagePaneLayout \
				gapHeight $gapHeight bottomToTop true]
			set rightPaneLayout [sequenceLayout VerticalStackLayout RightPane $pagePaneLayout \
				bottomToTop true]
			if [string equal $shape magnet] {
				set magnetPaneLayout [sequenceLayout VerticalStackLayout MagnetPane $leftPaneLayout \
					fillAlgorithm equalFill bottomToTop true]
				set bottomPaneLayout [sequenceLayout HorizontalStackLayout BottomPane $magnetPaneLayout \
					gapWidth $gapWidth fillAlgorithm equalFill]
				set ownerParentLayout $magnetPaneLayout
				# Minor headings.
				if {![$pageLayoutDetails has adjustmentHasHeading]} {set adjustmentHasHeading 1}
				if {![$pageLayoutDetails has retreatHasHeading]} {set retreatHasHeading 1}
				# Paths
				set ownerPath {PagePane LeftPane MagnetPane}
				set adjustmentPath {PagePane LeftPane MagnetPane BottomPane}
				set retreatPath {PagePane LeftPane MagnetPane BottomPane}
			} else {
				set bottomPaneLayout [sequenceLayout HorizontalStackLayout BottomPane $leftPaneLayout \
					gapWidth $gapWidth fillAlgorithm equalFill]
				set ownerParentLayout $bottomPaneLayout
				# Paths
				set ownerPath {PagePane LeftPane BottomPane}
				set adjustmentPath {PagePane LeftPane BottomPane}
				set retreatPath {PagePane LeftPane BottomPane}
			}
			set imageParentLayout $leftPaneLayout
			set adjustmentParentLayout $bottomPaneLayout
			set retreatParentLayout $bottomPaneLayout
			set orderParentLayout $rightPaneLayout
			set titleParentLayout $rightPaneLayout
			# Paths
			set imagePath {PagePane LeftPane}
			set orderPath {PagePane RightPane} 
			set titlePath {PagePane RightPane}
		} default {
			assert 0 {
				Unknown box: <$cornerBox>. Should be one of owners, adjustments, retreats or orders.
			}
		}
	} side {
		# Put all boxes on one side of the image.
		linit [lrange $layout 1 end] {position shape} {right flat}
		switch $position right {
			set pagePaneLayout [decorateLayout HorizontalStackLayout PagePane $pageLayout \
				gapWidth $gapWidth leftToRight false]
			set rightPaneLayout [sequenceLayout VerticalStackLayout RightPane $pagePaneLayout \
				fillAlgorithm equalFill bottomToTop true]
			set imageParentLayout $pagePaneLayout
			# Paths
			set imagePath {PagePane}
			switch $shape flat {
				set ownerParentLayout $rightPaneLayout
				set adjustmentParentLayout $rightPaneLayout
				set retreatParentLayout $rightPaneLayout
				# Paths
				set ownerPath {PagePane RightPane}
				set adjustmentPath {PagePane RightPane}
				set retreatPath {PagePane RightPane}
			} fold {
				set bottomPaneLayout [sequenceLayout VerticalStackLayout BottomPane $rightPaneLayout \
					bottomToTop true]
				set centerPaneLayout [sequenceLayout HorizontalStackLayout CenterPane $rightPaneLayout \
					leftToRight false fillAlgorithm equalFill]
				set ownerParentLayout $bottomPaneLayout
				set adjustmentParentLayout $centerPaneLayout
				set retreatParentLayout $centerPaneLayout
				# Paths
				set ownerPath {PagePane RightPane BottomPane}
				set adjustmentPath {PagePane RightPane CenterPane}
				set retreatPath {PagePane RightPane CenterPane}
			} default {
				assert 0 {
					Unknown shape: <$shape>. Should be one of flat or fold.
				}
			}
			set orderParentLayout $rightPaneLayout
			set titleParentLayout $rightPaneLayout
			# Paths
			set orderPath {PagePane RightPane}
			set titlePath {PagePane RightPane}
			# Minor headings.
			if {![$pageLayoutDetails has adjustmentHasHeading]} {set adjustmentHasHeading 1}
			if {![$pageLayoutDetails has retreatHasHeading]} {set retreatHasHeading 1}
			if {![$pageLayoutDetails has ownerHasHeading]} {set ownerHasHeading 1}
		} bottom {
			set pagePaneLayout [decorateLayout VerticalStackLayout PagePane $pageLayout \
				gapHeight $gapHeight bottomToTop true]
			set bottomPaneLayout [sequenceLayout HorizontalStackLayout BottomPane $pagePaneLayout \
				gapWidth $gapWidth fillAlgorithm equalFill]
			set leftPaneLayout [sequenceLayout VerticalStackLayout LeftPane $bottomPaneLayout \
				bottomToTop true fillAlgorithm equalFill]
			set imageParentLayout $pagePaneLayout
			set ownerParentLayout $leftPaneLayout
			set titleParentLayout $leftPaneLayout
			# Paths
			set imagePath {PagePane}
			set ownerPath {PagePane BottomPane LeftPane}
			set titlePath {PagePane BottomPane LeftPane}
			switch $shape flat {
				set adjustmentParentLayout $bottomPaneLayout
				set retreatParentLayout $bottomPaneLayout
				# Paths
				set adjustmentPath {PagePane BottomPane}
				set retreatPath {PagePane BottomPane}
			} fold {
				set centerPaneLayout [sequenceLayout VerticalStackLayout CenterPane $bottomPaneLayout \
					bottomToTop false fillAlgorithm equalFill]
				set adjustmentParentLayout $centerPaneLayout
				set retreatParentLayout $centerPaneLayout
				# Paths
				set adjustmentPath {PagePane BottomPane CenterPane}
				set retreatPath {PagePane BottomPane CenterPane}
				# Minor headings.
				if {![$pageLayoutDetails has retreatHasHeading]} {set retreatHasHeading 1}
			} magnet {
				set centerPaneLayout [sequenceLayout HorizontalStackLayout CenterPane $leftPaneLayout \
					leftToRight true fillAlgorithm equalFill]
				set adjustmentParentLayout $centerPaneLayout
				set retreatParentLayout $centerPaneLayout
				# Paths
				set adjustmentPath {PagePane BottomPane LeftPane CenterPane}
				set retreatPath {PagePane BottomPane LeftPane CenterPane}
				# Minor headings.
				if {![$pageLayoutDetails has adjustmentHasHeading]} {set adjustmentHasHeading 1}
				if {![$pageLayoutDetails has retreatHasHeading]} {set retreatHasHeading 1}
			} default {
				assert 0 {
					Unknown shape: <$shape>. Should be one of flat, fold or magnet.
				}
			}
			set orderParentLayout $bottomPaneLayout
			# Paths
			set orderPath {PagePane BottomPane} 
		} default {
			assert 0 {
				Unknown side: <$position>. Should be one of right or bottom.
			}
		}
	} default {
		assert 0 {
			Unknown layout: <$layout>. Should be one of image, corner or side.
		}
	}

	set imageGridLayout [insertLayout GridLayout ImageGrid $imageParentLayout \
		cellWidth $cellWidth cellHeight $cellHeight fitWidth 2 fitHeight 2]
	set imageFrameLayout [decorateLayout FrameLayout ImageFrame $imageGridLayout \
		marginWidth $imageFrameMarginWidth marginHeight $imageFrameMarginHeight fitWidth 2 fitHeight 2]
	createBorder [expr $drawLayoutBorder & 1] ImageFrame $drawLayoutBorders $pageLayout [concat $imagePath ImageGrid ImageFrame] $acts {} \$BorderColor [$colorTracker addColor Brown $drawLayoutBorder] 
	set imageLayout [decorateLayout ImageLayout Image $imageFrameLayout \
		imageWidth $imageWidth imageHeight $imageHeight widthPriority 5 heightPriority 5 \
		\$FrameLeft {$Left $FrameThickness $MarginWidth sub $FrameOverlap max add} \
		\$FrameBottom {$Bottom $FrameThickness $MarginHeight sub $FrameOverlap max add} \
		\$FrameWidth {$Width $FrameThickness $MarginWidth sub $FrameOverlap max 2 mul sub} \
		\$FrameHeight {$Height $FrameThickness $MarginHeight sub $FrameOverlap max 2 mul sub} \
	]
	createBorder [expr $drawLayoutBorder & 1] Image $drawLayoutBorders $pageLayout [concat $imagePath ImageGrid ImageFrame Image] $acts {} \$BorderColor [$colorTracker addColor Yellow $drawLayoutBorder] 
	$pageLayout addReference Map [concat $imagePath ImageGrid ImageFrame Image] {
		Left Bottom Width Height ImageScale
		FrameLeft FrameBottom FrameWidth FrameHeight
	}

	if [string length $ownerParentLayout] {
		insertReportLayout Owner $ownerParentLayout $acts $ownerHasHeading $ownerColumns $ownerAllowsOverlap \
			$cellWidth $cellHeight $ownerLineLength $ownerBoxLength \
			$ownerHeading OwnerReport WriteOwner $ownerTransform \
			$drawLayoutBorder $drawLayoutBorders $pageLayout $ownerPath [list \$BorderColor [$colorTracker addColor Mauve $drawLayoutBorder]] \
			widthPriority 3 heightPriority 2
	} else {
		muteReport $pageLayout OwnerReport WriteOwner
	}
	if [string length $adjustmentParentLayout] {
		insertReportLayout Adjustment $adjustmentParentLayout $acts $adjustmentHasHeading $adjustmentColumns $adjustmentAllowsOverlap \
			$cellWidth $cellHeight $adjustmentLineLength $adjustmentBoxLength \
			$adjustmentHeading AdjustReport WriteAdjust $adjustmentTransform \
			$drawLayoutBorder $drawLayoutBorders $pageLayout $adjustmentPath [list \$BorderColor [$colorTracker addColor Red $drawLayoutBorder]] \
			widthPriority 4 heightPriority 3
	} else {
		muteReport $pageLayout AdjustReport WriteAdjust
	}
	if [string length $retreatParentLayout] {
		insertReportLayout Retreat $retreatParentLayout $acts $retreatHasHeading $retreatColumns $retreatAllowsOverlap \
			$cellWidth $cellHeight $retreatLineLength $retreatBoxLength \
			$retreatHeading RetreatReport WriteRetreat $retreatTransform \
			$drawLayoutBorder $drawLayoutBorders $pageLayout $retreatPath [list \$BorderColor [$colorTracker addColor Green $drawLayoutBorder]] \
			widthPriority 1 heightPriority 4
	} else {
		muteReport $pageLayout RetreatReport WriteRetreat
	}
	if [string length $orderParentLayout] {
		insertReportLayout Order $orderParentLayout $acts $orderHasHeading $orderColumns $orderAllowsOverlap \
			$cellWidth $cellHeight $orderLineLength $orderBoxLength \
			$orderHeading OrderReport WriteOrder $orderTransform \
			$drawLayoutBorder $drawLayoutBorders $pageLayout $orderPath [list \$BorderColor [$colorTracker addColor Orange $drawLayoutBorder]] \
			widthPriority 2 heightPriority 1
	} else {
		muteReport $pageLayout OrderReport WriteOrder
	}
	if [string length $titleParentLayout] {
		sequenceTitleLayout Title $titleParentLayout $acts \
			$cellWidth $cellHeight \
			$boardTitleWidth $boardTitleHeight \
			$gameTitleWidth $gameTitleHeight \
			$drawLayoutBorder $drawLayoutBorders $pageLayout $titlePath [list \$BorderColor [$colorTracker addColor LightBlue $drawLayoutBorder]]
	} else {
		muteTitle $pageLayout
	}
		
	return $pageLayout
}

proc printLayout {name layout {indent 0} {top {}}} {
	set info ""
	for {set cnt 0} {$cnt < $indent} {incr cnt} {
		append info "| "
	}
	if {![string length $top]} {
		set top [$layout getHeight]
	}
	if {[catch {append info "$name \"$layout\"" \
			" iw: [Story::dedouble [$layout getInitialWidth]] ih: [Story::dedouble [$layout getInitialHeight]]" \
			" w: [Story::dedouble [$layout getWidth]] h: [Story::dedouble [$layout getHeight]]" \
			" l: [Story::dedouble [$layout getLeft]] t: [Story::dedouble [expr $top - [$layout getTop]]]" \
			" r: [Story::dedouble [$layout getRight]] b: [Story::dedouble [expr $top - [$layout getBottom]]]"} msg]} {
		append info "$name \"$layout\" incomplete"
	}
	inform $info
	foreach {childName childLayout} [[$layout getSequence] get] {
		if {[$childLayout isa Layout]} {
			printLayout $childName $childLayout [expr $indent + 1] $top
		}
	}
}

proc findLayout {layout elementName} {
	foreach {childName childLayout} [[$layout getSequence] get] {
		if {[$childLayout isa Layout]} {
			if {[string eq $childName $elementName]} {
				return $childLayout
			}
			set elementLayout [findLayout $childLayout $elementName]
			if {[string length $elementLayout]} {return $elementLayout}
		}
	}
	return {}
}

proc getLayoutElementBBox {name layout elementName} {
	if {[string eq $name $elementName]} {
		set elementLayout $layout
	} else {
		set elementLayout [findLayout $layout $elementName]
	}
	if {![string length $elementLayout]} {
		inform "Element $elementName not found in $name"
	} elseif {[catch {
		set top [$layout getHeight]
	} msg]} {
		inform "Layout $name incomplete"
	} elseif {[catch {
		set bbox [list \
			[Story::roundDown [$elementLayout getLeft] 1] \
			[Story::roundDown [expr $top - [$elementLayout getTop]] 1] \
			[Story::roundUp [$elementLayout getRight] 1] \
		 	[Story::roundUp [expr $top - [$elementLayout getBottom]] 1] \
		]
	} msg]} {
		inform "Element $elementName incomplete"
	} else {
		return $bbox
	}
	return {}
}